iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0
Modern Web

從 Next.js 開始的 Functional Programming系列 第 28

D28 - 管理依賴注入 (二)

  • 分享至 

  • xImage
  •  

昨天我們創建了四個 Layer,今天跟大家分享如何把多個它們組合起來,並最終提供給需要的 Effect 函式。

https://ithelp.ithome.com.tw/upload/images/20231013/201586158A1JgWwT81.png

組合 Layer 有兩種方法,分別是 Merging,還有 Composing。

Merging

Merging 用於兩個沒有依賴關係的 Layer 相互結合,例如上圖,MongoDB Service 和 MinIO Service 沒有依賴關係,所以我們可以用 Layer.merge 把它們合起來,像是以下這樣

const PersistenceLayer = Layer.merge(MongoLayer, MinIoSLayer)

合併後的 Layer 的型別會變成

Layer.Layer<EnvService, never, MongoService | MinIoService>

更通用一點來說,我們假設有兩個 Layer ,他們各自有不同的依賴與不同的輸出

Layer.Layer<A1, never, B1> //Layer1
Layer.Layer<A2, never, B2> //Layer2

那最後經過 merge 操作,會變成下面這樣

Layer.Layer<A1 | A2, never, B1 | B2> 

新產生的 Layer 會同時兼具他們的輸入與輸出

用示意圖總結,經過合併後我們可以想像原本的兩個服務合成了一個新的服務,最終使依賴關係變成了如下的線性排列。

https://ithelp.ithome.com.tw/upload/images/20231013/201586153DlqWIUPcK.png

Composing

像是上面這種排列方式,其實我們在 D05 就有提過類似的概念,也就是 pipe 還有 flow。只是因為服務的提供關係,我們要把順序反過來。想像最下層服務需要上層的服務,結合以後又再需要更上層的服務,最後產生出一個新的服務,就跟我們在用 pipe 做函式的串接非常相似,只是串接順序改變,還有串接的目標變成另外一個抽象型別而已。

具體來說可以這樣做

const FileLayerLive = pipe(
  FileServiceLayer,
  Layer.use(PersistanceLayer),
  Layer.use(EnvLayer)
)

FileServiceLayer 本身型別是

Layer.Layer<MinIoService | MongoService, never, FileService>

串接 PersistanceLayer 以後輸出型別變成

Layer.Layer<EnvService, never, FileService>

最後完整的輸出型別變成

Layer.Layer<never, never, FileService>

Providing

前面做了好多準備工作就是為了這一刻,假設我們有一個功能,新增課程

const program = pipe(
  FileService.context,
  Effect.flatMap((fs) => fs.createCourse('data')({} as unknown as Course)),
)
Effect.Effect<FileService, FileServiceError, Course>

最終產生的型別請參考上方程式碼區塊。這個型別表示他需要提供 FileService 才可以正常運行,可是 FileService 本身又需要另外的 PersistenceService 作為依賴,而 PersistenceService 又有 EnvService 作為依賴,這樣套下去有點麻煩。幸好我們一開始就利用 Layer 把依賴注入的工作都整合在一起,最終只要多加一行 Effect.provide(FileServiceLive) 就可以簡單完成依賴注入。

const program = pipe(
  FileService.context,
  Effect.flatMap((fs) => fs.createCourse('data')({} as unknown as Course)),
  Effect.provide(FileServiceLive)
)
Effect.Effect<never, FileServiceError, Course>

最終 Effect<R, E, A> 裡面的 R 變成了 never,我們只要再搭配 runPromise 之類的運行函式,就可以把程式執行起來。


上一篇
D27 - 管理依賴注入 (一)
下一篇
D29 - 副作用與復原
系列文
從 Next.js 開始的 Functional Programming30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言